use queue::queue::Queue;

#[test]
fn test_queue_new_free() {
    // Test creating and destroying a queue
    let mut queue = Queue::<i32>::new();
    drop(queue);

    // Test adding values and then destroying
    let mut queue = Queue::new();
    for _ in 0..1000 {
        queue.push_head(1);
    }
    drop(queue);
}

#[test]
fn test_queue_push_head() {
    let mut queue = Queue::new();

    // Add some values
    for _ in 0..1000 {
        queue.push_head(1);
        queue.push_head(2);
        queue.push_head(3);
        queue.push_head(4);
    }

    assert!(!queue.is_empty());

    // Check values come out of the tail properly
    assert_eq!(queue.pop_tail(), Some(1));
    assert_eq!(queue.pop_tail(), Some(2));
    assert_eq!(queue.pop_tail(), Some(3));
    assert_eq!(queue.pop_tail(), Some(4));

    // Check values come back out of the head properly
    assert_eq!(queue.pop_head(), Some(4));
    assert_eq!(queue.pop_head(), Some(3));
    assert_eq!(queue.pop_head(), Some(2));
    assert_eq!(queue.pop_head(), Some(1));

    drop(queue);
}

#[test]
fn test_queue_pop_head() {
    // Check popping off an empty queue
    let mut queue = Queue::<i32>::new();
    assert_eq!(queue.pop_head(), None);
    drop(queue);

    // Pop off all the values from the queue
    let mut queue = Queue::new();
    for _ in 0..1000 {
        queue.push_head(1);
        queue.push_head(2);
        queue.push_head(3);
        queue.push_head(4);
    }

    while !queue.is_empty() {
        assert_eq!(queue.pop_head(), Some(4));
        assert_eq!(queue.pop_head(), Some(3));
        assert_eq!(queue.pop_head(), Some(2));
        assert_eq!(queue.pop_head(), Some(1));
    }

    assert_eq!(queue.pop_head(), None);
    drop(queue);
}

#[test]
fn test_queue_peek_head() {
    // Check peeking into an empty queue
    let queue = Queue::<i32>::new();
    assert_eq!(queue.peek_head(), None);
    drop(queue);

    // Pop off all the values from the queue, making sure that peek has the correct value beforehand
    let mut queue = Queue::new();
    for _ in 0..1000 {
        queue.push_head(1);
        queue.push_head(2);
        queue.push_head(3);
        queue.push_head(4);
    }

    while !queue.is_empty() {
        assert_eq!(queue.peek_head(), Some(&4));
        assert_eq!(queue.pop_head(), Some(4));
        assert_eq!(queue.peek_head(), Some(&3));
        assert_eq!(queue.pop_head(), Some(3));
        assert_eq!(queue.peek_head(), Some(&2));
        assert_eq!(queue.pop_head(), Some(2));
        assert_eq!(queue.peek_head(), Some(&1));
        assert_eq!(queue.pop_head(), Some(1));
    }

    assert_eq!(queue.peek_head(), None);
    drop(queue);
}

#[test]
fn test_queue_push_tail() {
    let mut queue = Queue::new();

    // Add some values
    for _ in 0..1000 {
        queue.push_back(1);
        queue.push_back(2);
        queue.push_back(3);
        queue.push_back(4);
    }

    assert!(!queue.is_empty());

    // Check values come out of the head properly
    assert_eq!(queue.pop_head(), Some(1));
    assert_eq!(queue.pop_head(), Some(2));
    assert_eq!(queue.pop_head(), Some(3));
    assert_eq!(queue.pop_head(), Some(4));

    // Check values come back out of the tail properly
    assert_eq!(queue.pop_tail(), Some(4));
    assert_eq!(queue.pop_tail(), Some(3));
    assert_eq!(queue.pop_tail(), Some(2));
    assert_eq!(queue.pop_tail(), Some(1));

    drop(queue);
}

#[test]
fn test_queue_pop_tail() {
    // Check popping off an empty queue
    let mut queue = Queue::<i32>::new();
    assert_eq!(queue.pop_tail(), None);
    drop(queue);

    // Pop off all the values from the queue
    let mut queue = Queue::new();
    for _ in 0..1000 {
        queue.push_head(1);
        queue.push_head(2);
        queue.push_head(3);
        queue.push_head(4);
    }

    while !queue.is_empty() {
        assert_eq!(queue.pop_tail(), Some(1));
        assert_eq!(queue.pop_tail(), Some(2));
        assert_eq!(queue.pop_tail(), Some(3));
        assert_eq!(queue.pop_tail(), Some(4));
    }

    assert_eq!(queue.pop_tail(), None);
    drop(queue);
}

#[test]
fn test_queue_peek_tail() {
    // Check peeking into an empty queue
    let queue = Queue::<i32>::new();
    assert_eq!(queue.peek_tail(), None);
    drop(queue);

    // Pop off all the values from the queue, making sure that peek has the correct value beforehand
    let mut queue = Queue::new();
    for _ in 0..1000 {
        queue.push_head(1);
        queue.push_head(2);
        queue.push_head(3);
        queue.push_head(4);
    }

    while !queue.is_empty() {
        assert_eq!(queue.peek_tail(), Some(&1));
        assert_eq!(queue.pop_tail(), Some(1));
        assert_eq!(queue.peek_tail(), Some(&2));
        assert_eq!(queue.pop_tail(), Some(2));
        assert_eq!(queue.peek_tail(), Some(&3));
        assert_eq!(queue.pop_tail(), Some(3));
        assert_eq!(queue.peek_tail(), Some(&4));
        assert_eq!(queue.pop_tail(), Some(4));
    }

    assert_eq!(queue.peek_tail(), None);
    drop(queue);
}

#[test]
fn test_queue_is_empty() {
    let mut queue = Queue::new();

    assert!(queue.is_empty());

    queue.push_head(1);

    assert!(!queue.is_empty());

    queue.pop_head();

    assert!(queue.is_empty());

    queue.push_back(1);

    assert!(!queue.is_empty());

    queue.pop_tail();

    assert!(queue.is_empty());

    drop(queue);
}